package config

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"runtime"
	"strings"

	"gopkg.in/yaml.v2"

	"iot-base/common/logger"

	"github.com/aidarkhanov/nanoid/v2"
	"go.uber.org/zap"
)

//RedisInfo redis连接字
type RedisInfo struct {
	Addr     string `json:"addr"`
	UserName string `json:"username"`
	Password string `json:"password"`
	Index    int    `json:"index"`
}

//DBCfg 数据库配置信息
type DBCfg struct {
	DBAddr      string    `json:"dbAddr"`
	UserName    string    `json:"username"`
	Password    string    `json:"password"`
	DBName      string    `json:"dbName"`
	Type        string    `json:"type"`
	RedisOption RedisInfo `json:"redisInfo"`
	AlarmSavePriod    int       `json:"alarmSavePriod" yaml:"alarmSaveProid"`
	RealDataSavePriod int       `json:"realDataSaveProid" yaml:"realDataSaveProid"`
}

//MQTTOption mqtt配置信息
type MQTTCfg struct {
	IsMqttConnection bool   `json:"is_mqtt_connection"` //云端是否连接消息队列
	Addr             string `json:"addr"`
	UN               string `json:"un"`
	PWD              string `json:"pwd"`
	HTInterval       int    `json:"htInterval"`
	TopicPrefix      string `json:"topicPrefix" yaml:"topicPrefix"`
}

//SelfCfg 自身信息
type SelfCfg struct {
	ID            string `json:"id"`
	OuterHttpAddr string `json:"outerHttpAddr"`
	MaintainPort  int    `yaml:"maintainport"`
	Name          string `json:"name"`
	//OutHttpToken  string
}

//MediaAddr 多媒体地址
/*
type MediaAddr struct {
	Addr     string `json:"addr"`
	WSPort   int    `json:"wsPort"`
	HTTPPort int    `json:"httpPort"`
	RTSPPort int    `json:"rtspPort"`
	RTMPPort int    `json:"rtmpPort"`
}*/

var (
	//DBOption 数据库配置信息
	DBOption DBCfg

	//SelfOption 自身信息
	SelfOption SelfCfg

	//MQTTOption mqtt配置信息
	MQTTOption MQTTCfg

	//MediaOption 转发服务地址
	//MediaOption MediaAddr
)

type CONFIG struct {
	//DBOption 数据库配置信息
	DBOption *DBCfg `json:"db"`

	//SelfOption 自身信息
	SelfOption *SelfCfg `json:"self"`

	//MQTTOption mqtt配置信息
	MQTTOption *MQTTCfg `json:"mqtt"`

	//MediaOption 转发服务地址
	//MediaOption *MediaAddr `json:"media"`
}

//GetAllConfig 获取配置
func GetAllConfig() CONFIG {
	return CONFIG{
		DBOption:   &DBOption,
		SelfOption: &SelfOption,
		MQTTOption: &MQTTOption,
		//MediaOption: &MediaOption,
	}
}

//postgres://postgres:xh123$%^@ /iotbase?sslmode=disable
func loadDefaultOption() {
	DBOption.DBAddr = "127.0.0.1:5432"
	DBOption.UserName = "postgres"
	DBOption.Password = "iotbasePWD"
	if PType == "edge" {
		DBOption.DBName = "iotbase_edge"
		CFGPATH = "../../../cfgEdge/"
		DBOption.RedisOption.Index = 1
		SelfOption.MaintainPort = 16666
	} else {
		DBOption.DBName = "iotbase"
		CFGPATH = "../../../cfg/"
		DBOption.RedisOption.Index = 0
		SelfOption.MaintainPort = 18866
	}

	DBOption.Type = "postgres"
	DBOption.RedisOption.Addr = "127.0.0.1:6379"
	MQTTOption.Addr = "tcp://192.168.10.248:1883"
	MQTTOption.UN = "iotbase"
	MQTTOption.PWD = "Mima2021@)@!"
	MQTTOption.HTInterval = 20
	MQTTOption.TopicPrefix = "/scenery/"
	if PType == "cloud" {
		MQTTOption.IsMqttConnection = false
	} else {
		MQTTOption.IsMqttConnection = true
	}
	/*
		MediaOption.Addr = "127.0.0.1"
		MediaOption.WSPort = 2555
		MediaOption.HTTPPort = 10080
		MediaOption.RTSPPort = 2554
		MediaOption.RTMPPort = 1935
	*/

	//DBOption.RedisOption

}

//GetCloudTopic 获取云端topic
func GetCloudTopic() string {
	return "iot" + MQTTOption.TopicPrefix + "cloud/"
}

//GetEdgeTopic 获取边缘topic
func GetEdgeTopic() string {
	return "iot" + MQTTOption.TopicPrefix + "edge/"
}

//获取本地的topic
func GetLocalTopic() string {
	if PType == "edge" {
		return GetEdgeTopic()
	}
	return GetCloudTopic()
}

func readInfo(option interface{}, filename string) {
	jsonFile, err := os.Open(filename)
	if err != nil {
		logger.Log.Error("read file cfg error", zap.Error(err), zap.String("filename", filename))
		SaveAll()
		return
	}
	defer jsonFile.Close()
	byteValue, _ := ioutil.ReadAll(jsonFile)
	//json.Unmarshal([]byte(byteValue), option)
	yaml.Unmarshal([]byte(byteValue), option)

}

func uuidString() string {
	u2, err := nanoid.New()
	if err != nil {
		logger.Log.Error("read file cfg error", zap.Error(err))
		return "1234"
	}
	return fmt.Sprintf("%v", u2)
}

func defaultSelfID() string {
	var strID string
	if runtime.GOOS == "linux" {
		cmd := exec.Command("cat", "/sys/class/net/eth0/address")
		stdout, err := cmd.StdoutPipe()
		if err != nil { //获取输出对象，可以从该对象中读取输出结果
			fmt.Println(err)
			return uuidString()
		}
		defer stdout.Close()                // 保证关闭输出流
		if err := cmd.Start(); err != nil { // 运行命令
			fmt.Println(err)
			return uuidString()
		}
		opBytes, err := ioutil.ReadAll(stdout)
		if err != nil { // 读取输出结果
			return uuidString()
		}
		strID = strings.Replace(string(opBytes[:]), "\n", "", -1)
		if strID == "" {
			return uuidString()
		}
	} else {
		interfaces, err := net.Interfaces()
		if err != nil {
			panic("error while getting interface for net: " + err.Error())

		}
		//for _, inter := range interfaces {
		//fmt.Println(inter.Name)
		inter := interfaces[0]
		strID = inter.HardwareAddr.String() //获取本机MAC地址

	}
	strID = strings.Replace(strID, "\r", "", -1)
	strID = strings.Replace(strID, " ", "", -1)
	strID = strings.Replace(strID, ":", "", -1)
	return strID
}

//CFGPATH 配置目录
var CFGPATH = "../../../cfg/"

func init() {
	//logger.Log.Info("read info from" + CFGPATH)
	Reload()
}

//Reload 重新加载配置文件
func Reload() {
	logger.SLog.Warn("--------------begin read cfg-------", PType)
	loadDefaultOption()

	readInfo(&DBOption, CFGPATH+"db.yaml")
	readInfo(&SelfOption, CFGPATH+"self.yaml")
	readInfo(&MQTTOption, CFGPATH+"mqtt.yaml")
	typename := PType

	if SelfOption.ID == "" {
		SelfOption.ID = defaultSelfID() + "@" + typename
		save(SelfOption, CFGPATH+"self.yaml")
	}
	_, err := os.Stat(CFGPATH + "db.yaml")
	if err != nil {
		save(DBOption, CFGPATH+"db.yaml")
	}
	_, err = os.Stat(CFGPATH + "mqtt.yaml")
	if err != nil {
		save(MQTTOption, CFGPATH+"mqtt.yaml")
	}
	fmt.Println("***********", CFGPATH, DBOption, SelfOption, MQTTOption)

}

func save(option interface{}, filename string) {
	os.Mkdir(CFGPATH, os.ModePerm)
	filePtr, err := os.Create(filename)
	if err != nil {
		fmt.Println("文件创建失败", err.Error())
		return
	}
	defer filePtr.Close()
	//encoder := json.NewEncoder(filePtr)
	//encoder.Encode(option)
	d, _ := yaml.Marshal(option)
	filePtr.WriteString(string(d))
}

//RemoveFile 删除配置文件
func RemoveFile() {
	os.Remove(CFGPATH + "db.yaml")
	os.Remove(CFGPATH + "self.yaml")
	os.Remove(CFGPATH + "mqtt.yaml")
}

//SaveAll 保存所有文件
func SaveAll() {
	save(DBOption, CFGPATH+"db.yaml")
	save(SelfOption, CFGPATH+"self.yaml")
	save(MQTTOption, CFGPATH+"mqtt.yaml")
}

func SaveByNewCfg(cfg CONFIG) {
	save(cfg.DBOption, CFGPATH+"db.yaml")
	save(cfg.SelfOption, CFGPATH+"self.yaml")
	save(cfg.MQTTOption, CFGPATH+"mqtt.yaml")
}

//SetSqlite 设置Sqlite名称
func SetSqlite(filename string) {
	DBOption.DBAddr = "sqlite3://./" + filename
	save(DBOption, CFGPATH+"db")
}
